from typing_extensions import List, Annotated

from fastapi import Depends, Request, HTTPException, Path
from sqlalchemy import select, exists, delete, update

from core.database import db_session
from core.models import Member, BoardNew, Scrap, WriteBaseModel
from lib.board_lib import is_owner, FileCache
from lib.common import remove_query_params, set_url_query_params
from service.board_file_service import BoardFileService
from service.point_service import PointService
from .board import BoardService


class DeletePostService(BoardService):
    """
    删除帖子处理类
    """

    def __init__(
        self,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
        bo_table: Annotated[str, Path(...)],
        wr_id: Annotated[int, Path(...)],
    ):
        super().__init__(request, db, bo_table)
        self.wr_id = wr_id
        self.write = self.get_write(wr_id)
        self.write_member_mb_no = self.db.scalar(select(Member.mb_no).where(Member.mb_id == self.write.mb_id))
        self.write_member = self.db.get(Member, self.write_member_mb_no)
        self.write_member_level = getattr(self.write_member, "mb_level", 1)
        self.file_service = file_service
        self.point_service = point_service

    @classmethod
    async def async_init(
        cls,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
        bo_table: Annotated[str, Path(...)],
        wr_id: Annotated[int, Path(...)],
    ):
        instance = cls(request, db, file_service, point_service, bo_table, wr_id)
        return instance

    def validate_level(self, with_session: bool = True):
        """权限验证"""
        if self.member.admin_type == "super":
            return

        if self.member.admin_type and self.write_member_level > self.member.level:
            self.raise_exception(status_code=403, detail="您无法删除高于自己的帖子.")
        elif self.write.mb_id and not is_owner(self.write, self.member.mb_id):
            self.raise_exception(status_code=403, detail="您只能删除自己的帖子.", )

        if not self.write.mb_id:
            if with_session and not self.request.session.get(f"ss_delete_{self.bo_table}_{self.wr_id}"):
                url = f"/bbs/password/delete/{self.bo_table}/{self.wr_id}"
                query_params = remove_query_params(self.request, "token")
                self.raise_exception(status_code=403, detail="您无权删除非成员帖子.", url=set_url_query_params(url, query_params))
            elif not with_session:
                self.raise_exception(status_code=403, detail="您无权删除非成员帖子.")
        
    def validate_exists_reply(self):
        """有答案时不能删除"""
        exists_reply = self.db.scalar(
            exists(self.write_model)
            .where(
                self.write_model.wr_reply.like(f"{self.write.wr_reply}%"),
                self.write_model.wr_num == self.write.wr_num,
                self.write_model.wr_is_comment == 0,
                self.write_model.wr_id != self.wr_id
            )
            .select()
        )
        if exists_reply:
            self.raise_exception(detail="您无法删除有答案的帖子. 首先，请删除答案。.", status_code=403)

    def validate_exists_comment(self):
         """删除的评论数不能超过公告板设置中设置的数量"""
         if not self.is_delete_by_comment(self.wr_id):
            self.raise_exception(detail=f"与本文相关的评论 {self.board.bo_count_delete}无法删除，因为它的存在超过.", status_code=403)

    def delete_write(self):
        """处理帖子删除"""
        write_model = self.write_model
        db = self.db
        bo_table = self.bo_table
        board = self.board

        # 原创写作 + 评论
        delete_write_count = 0
        delete_comment_count = 0
        writes: List[WriteBaseModel] = db.scalars(
            select(write_model)
            .filter_by(wr_parent=self.wr_id)
            .order_by(write_model.wr_id)
        ).all()
        for write in writes:
            # 删除原始
            if not write.wr_is_comment:
                # 删除单字母点
                if not self.point_service.delete_point(write.mb_id, bo_table, self.wr_id, "写作"):
                    self.point_service.save_point(write.mb_id, board.bo_write_point * (-1),
                                                    f"{board.bo_subject} {self.wr_id} 删除帖子")
                # 文件+删除缩略图
                self.file_service.delete_board_files(board.bo_table, self.wr_id)

                delete_write_count += 1
                # TODO: 删除designer缩略图
            else:
                # 删除评论点
                if not self.point_service.delete_point(write.mb_id, bo_table, self.wr_id, "评论"):
                    self.point_service.save_point(self.request, write.mb_id, board.bo_comment_point * (-1),
                                                  f"{board.bo_subject} {self.wr_id} 删除评论")

                delete_comment_count += 1

        # 原创写作+删除评论
        db.execute(delete(write_model).filter_by(wr_parent=self.wr_id))

        # 删除最近的帖子
        db.execute(delete(BoardNew).where(
            BoardNew.bo_table == bo_table,
            BoardNew.wr_parent == self.wr_id
        ))

        # 删除废料
        db.execute(delete(Scrap).filter_by(
            bo_table=bo_table,
            wr_id=self.wr_id
        ))

        # 删除公共
        board.bo_notice = self.set_board_notice(self.wr_id, False)

        # 更新帖子数量
        board.bo_count_write -= delete_write_count
        board.bo_count_comment -= delete_comment_count

        db.commit()
        db.close()

        # 删除最新的post缓存
        FileCache().delete_prefix(f'latest-{bo_table}')


class DeleteCommentService(DeletePostService):
    """删除注释处理类"""

    def __init__(
        self,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
        bo_table: Annotated[str, Path(...)],
        comment_id: Annotated[str, Path(...)],
    ):
        super().__init__(request, db, file_service, point_service, bo_table, comment_id)
        self.wr_id = comment_id
        self.comment = self.get_comment()

    @classmethod
    async def async_init(
        cls,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
        bo_table: Annotated[str, Path(...)],
        comment_id: Annotated[str, Path(...)],
    ):
        instance = cls(request, db, file_service, point_service, bo_table, comment_id)
        return instance

    def get_comment(self) -> WriteBaseModel:
        comment: WriteBaseModel = self.db.get(self.write_model, self.wr_id)
        if not comment:
            raise HTTPException(status_code=404, detail=f"{self.wr_id} : 这是一个不存在的评论.")

        if not comment.wr_is_comment:
            raise HTTPException(status_code=400, detail=f"{self.wr_id} : 这是一个帖子，不是评论.")

        return comment

    def check_authority(self, with_session: bool = True):
        """
        删除帖子权限验证
        - Template 如果您将其用于 with_session 因素是 True 作为一个值
          如果匿名评论 session验证权限通过.
        - API 如果您将其用于 with_session 因素是 False 用作值.
        """
        if self.member.admin_type:
            return

        # 匿名评论
        if not self.comment.mb_id:

            # API 当请求
            if not with_session:
                self.raise_exception(detail="您没有删除的权限.", status_code=403)

            # 当请求模板时
            session_name = f"ss_delete_comment_{self.bo_table}_{self.wr_id}"
            if self.request.session.get(session_name):
                return
            url = f"/bbs/password/comment-delete/{self.bo_table}/{self.wr_id}"
            query_params = remove_query_params(self.request, "token")
            self.raise_exception(detail="您没有删除的权限.", status_code=403, url=set_url_query_params(url, query_params))

        # 会员评论
        # 회원 댓글
        if not is_owner(self.comment, self.member.mb_id):
            self.raise_exception(detail="您只能删除自己的评论.", status_code=403)

    def delete_comment(self):
        """删除评论"""
        write_model= self.write_model

        # 删除评论
        self.db.delete(self.comment)

        # 减少对帖子的评论数量
        self.db.execute(
            update(write_model).values(wr_comment=write_model.wr_comment - 1)
            .where(write_model.wr_id == self.comment.wr_parent)
        )

        self.db.commit()


class ListDeleteService(BoardService):
    """
    用于一次删除多个帖子的类
    """

    def __init__(
        self,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
        bo_table: Annotated[str, Path(...)],
    ):
        super().__init__(request, db, bo_table)
        self.file_service = file_service
        self.point_service = point_service

    @classmethod
    async def async_init(
        cls,
        request: Request,
        db: db_session,
        file_service: Annotated[BoardFileService, Depends()],
        point_service: Annotated[PointService, Depends()],
        bo_table: Annotated[str, Path(...)],
    ):
        instance = cls(request, db, file_service, point_service, bo_table)
        return instance

    def delete_writes(self, wr_ids: list):
        """删除帖子列表"""
        write_model = self.write_model
        writes: List[WriteBaseModel] = self.db.scalars(
            select(write_model)
            .where(write_model.wr_id.in_(wr_ids))
        ).all()
        for write in writes:
            self.db.delete(write)
            # 删除积分点
            if not self.point_service.delete_point(write.mb_id, self.bo_table, write.wr_id, "写作"):
                self.point_service.save_point(write.mb_id, self.board.bo_write_point * (-1),
                                              f"{self.board.bo_subject} {write.wr_id} 删除帖子")

            # 删除文件
            self.file_service.delete_board_files(self.board.bo_table, write.wr_id)

            # TODO: 删除评论
        self.db.commit()

        # 删除最新文章缓存
        FileCache().delete_prefix(f'latest-{self.bo_table}')

        # TODO:添加删除帖子时需要删除的内容
